#include "SceneObjWriter.h"
#include <set>
#include <fstream>

void CSceneObjWriter::addSceneInfo(ptr<SSceneInfoGoldSrc> vSceneInfo)
{
    for (size_t i = 0; i < vSceneInfo->pScene->getActorNum(); ++i)
    {
        auto pActor = vSceneInfo->pScene->getActor(i);
        auto MeshData = pActor->getMesh()->getMeshData();
        auto pTexIndexArray = MeshData.getTexIndexArray();

        CIOImage::Ptr pImage = nullptr;
        if (!pTexIndexArray->empty())
        {
            uint32_t TexIndex = MeshData.getTexIndexArray()->get(0);
            auto pImage = vSceneInfo->TexImageSet[TexIndex];
        }

        ptr<SObjObject> pObjObject = make<SObjObject>();
        pObjObject->Name = pActor->getName();
        pObjObject->pVertexArray = MeshData.getVertexArray();
        pObjObject->pTexCoordArray = MeshData.getTexCoordArray();
        pObjObject->pImage = pImage;

        addObject(pObjObject);
    }
}

void CSceneObjWriter::addObject(ptr<SObjObject> vObject)
{
    m_ObjectSet.emplace_back(vObject);
}

void CSceneObjWriter::writeToFile(std::filesystem::path vFilePath)
{
    std::set<ptr<CIOImage>> ImageSet;
    uint64_t CurId = 1;

    std::filesystem::path MtlFileName = vFilePath.filename().replace_extension(".mtl");

    std::ofstream ObjFile(vFilePath);
    ObjFile << "# Generated by GoldSrc Renderer\n";
    ObjFile << "# https://gitee.com/allocblock/goldsrc-renderer \n";
    ObjFile << "usemtl " << MtlFileName << "\n";
    for (ptr<SObjObject> pObject : m_ObjectSet)
    {
        size_t VertexNum = pObject->pVertexArray->size();
        _ASSERTE(pObject->pImage);
        _ASSERTE(VertexNum % 3 == 0);
        _ASSERTE(VertexNum == pObject->pTexCoordArray->size());
        if (ImageSet.count(pObject->pImage) == 0)
        {
            ImageSet.insert(pObject->pImage);
        }

        ObjFile << "g " << pObject->Name << "\n";
        ObjFile << "usemtl " << pObject->pImage->getName() << "\n";

        for (size_t i = 0; i < VertexNum; ++i)
        {
            const auto& Vertex = pObject->pVertexArray->get(i);
            ObjFile << "v " << Vertex.x << " " << Vertex.y << " " << Vertex.z << "\n";
        }

        for (size_t i = 0; i < VertexNum; ++i)
        {
            const auto& TexCoord = pObject->pTexCoordArray->get(i);
            ObjFile << "vt " << TexCoord.x << " " << TexCoord.y << "\n";
        }

        for (size_t i = 0; i < VertexNum; i += 3)
        {
            ObjFile << "f " << CurId << "/" << CurId << " "
                << (CurId + 1) << "/" << (CurId + 1) << " "
                << (CurId + 2) << "/" << (CurId + 2) << "\n";
            CurId += 3;
        }
        ObjFile << "\n";
    }
    ObjFile.close();

    std::ofstream MtlFile(vFilePath.replace_extension(".mtl"));
    for (ptr<CIOImage> pImage : ImageSet)
    {
        MtlFile << "newmtl " << pImage->getName() << "\n";
        MtlFile << "Ka 0 0 0\n";
        MtlFile << "Kd 1 1 1\n";
        MtlFile << "d 1\n";
        MtlFile << "Ns 0\n";
        MtlFile << "illum 1\n";
        MtlFile << "map_Kd textures/" << pImage->getName() << ".bmp\n\n";
    }
    MtlFile.close();

    // save textures
    auto TextureDir = vFilePath.parent_path().append("textures");
    if (!std::filesystem::exists(TextureDir))
        std::filesystem::create_directory(TextureDir);

    for (ptr<CIOImage> pImage : ImageSet)
    {
        pImage->writeBMP(std::filesystem::path(TextureDir).append(pImage->getName() + ".bmp"));
    }
}
